home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / hapn.c < prev    next >
C/C++ Source or Header  |  1992-02-11  |  11KB  |  492 lines

  1. /*  Driver for HAPN-1 8273 card
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "iface.h"
  11. #include "hapn.h"
  12. #include "ax25.h"
  13. #include "trace.h"
  14.  
  15. struct hapn hapn[NHAPN];
  16. void ha0vec();
  17. void (*h_handle[])() = { ha0vec };
  18. int16 nhapn;
  19.  
  20. /*  send command to the 8273
  21.  *  "base" = base port of 8273
  22.  *  "cmd"  = command byte
  23.  *  "np"   = number of parameter bytes
  24.  *  "p1"   = first parameter (parameters are int)
  25.  */
  26. /*VARARGS3*/
  27. static
  28. cmd_8273(base, cmd, np, p1)
  29. int16 base;
  30. int cmd, np, p1;
  31. {
  32.     int *p;
  33.  
  34.     while(inportb(base+STA) & CBSY)
  35.         ;
  36.     outportb(base+CMD, cmd);
  37.     p = &p1;
  38.     while(np--){
  39.         while(inportb(base+STA) & CPBF)
  40.             ;
  41.         outportb(base+PAR, *p++);
  42.     }
  43. }
  44.  
  45. /*  Start receiver of 8273 */
  46. static
  47. hrxgo(hp)
  48. register struct hapn *hp;
  49. {
  50.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  51. }
  52.  
  53. /*  Interrupt service function.  Entered with hapn index
  54.  *  The "flag" variable is used in this routine to indicate a
  55.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  56.  *  the 8273 is reset.
  57.  */
  58. void
  59. haint(dev)
  60. int dev;
  61. {
  62.     register struct hapn *hp;
  63.     register int16 base;
  64.     char flag = 0;
  65.     void htxint(),hrxint();
  66.  
  67.     hp = &hapn[dev];
  68.     base = hp->base;
  69.  
  70.     /*  Check for TX interrupt  */
  71.     if(inportb(base+STA) & TXINT){
  72.         flag = 1;    /* Valid interrupt, set flag */
  73.         htxint(hp);
  74.     }
  75.     /*  Check for RX interrupt  */
  76.     if(inportb(base+STA) & RXINT){
  77.         flag = 1;    /* Valid interrupt, set flag */
  78.         hrxint(hp);
  79.     }
  80.     /* Check for unknown interrupt  */
  81.     if(!flag){
  82.         hp->badint++;    /* Increment error counter */
  83.         hapn_init(hp);    /* Reinitialise the 8273 */
  84.     }
  85. }
  86. /*  RX interrupt service
  87.  *  if status register bit "RXIRA" is set, interrupt is final,
  88.  *  otherwise, interrupt is data request
  89.  */
  90. static void
  91. hrxint(hp)
  92. register struct hapn *hp;
  93. {
  94.     register struct mbuf *bp;
  95.     register int16 base;
  96.     unsigned char results[10];
  97.  
  98.     hp->rxints++;
  99.     base = hp->base;
  100.  
  101.     if(inportb(base+STA) & RXIRA){
  102.         /* RX result interrupt
  103.          * If the result is a good frame 3 bytes need to be read
  104.          * If an error has occurred only one byte need to be read
  105.          */
  106.  
  107.         /* Read first result byte and test for good data */
  108.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  109.             /* Good result; read two more result bytes */
  110.             while((inportb(base + STA) & RXIRA) == 0)
  111.                 ;
  112.             /* Read second result byte */
  113.             results[1] = inportb(base + RXI);
  114.             /* Wait for third result byte  */
  115.             while((inportb(base + STA) & RXIRA) == 0)
  116.                 ;  
  117.             results[2] = inportb(base + RXI);/* Read it */
  118.  
  119.             /* Since this frame is ok put it on the queue */
  120.             enqueue(&hp->rcvq, hp->rcvbuf);
  121.             hp->rcvbuf = NULLBUF;
  122.             hp->rcvcnt++;
  123.             hp->rframes++;
  124.         } else {
  125.             /* Error termination
  126.              * Parse RIC and act accordingly
  127.              * Only one result byte returned on error
  128.              */
  129.             switch(results[0]){
  130.             case CRCERR:
  131.                 hp->crcerr++;
  132.                 break;
  133.             case ABORT_DET:
  134.                 hp->aborts++;
  135.                 break;
  136.             case DMA_OVRN:
  137.                 hp->dmaorun++;
  138.                 break;
  139.             case MEM_OVFL:
  140.                 hp->toobig++;
  141.                 break;
  142.             case CD_LOSS:
  143.                 hp->cdloss++;
  144.                 hapn_init(hp);    /* 8273 reset on cd error */
  145.                 break;
  146.             case RX_ORUN:
  147.                 hp->rxorun++;
  148.                 break;
  149.             }
  150.             /* Throw rx buffer contents away to start over */
  151.             hp->rcp = hp->rcvbuf->data;
  152.             hp->rcvbuf->cnt = 0;
  153.         }
  154.         /* Restart the receiver */
  155.         cmd_8273(base,RX_DISABLE,0);
  156.         hrxgo(hp);
  157.     } else {
  158.         /* RX data interrupt; allocate new rx buffer if none present */
  159.         if((bp = hp->rcvbuf) == NULLBUF){
  160.             bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  161.             if(bp == NULLBUF){
  162.                 /* No memory available */
  163.                 hp->nomem++;
  164.                 cmd_8273(base, RX_DISABLE, 0);
  165.                 hrxgo(hp);
  166.                 return;
  167.             }
  168.             /* Init buffer pointer */
  169.             hp->rcp = hp->rcvbuf->data;
  170.         }
  171.         /*  Barf if rx data is more than buffer can hold (should never
  172.          *  happen since 8273 is also counting bytes).
  173.          */
  174.         if(bp->cnt++ >= hp->bufsiz){
  175.             hp->toobig++;
  176.             cmd_8273(base, RX_DISABLE, 0);
  177.             hrxgo(hp);
  178.             free_p(bp);
  179.             hp->rcvbuf = NULLBUF;
  180.             return;
  181.         }
  182.         /* Store the received byte */
  183.         *hp->rcp++ = inportb(base+RXD);
  184.     }
  185. }
  186.  
  187. /*  test for busy channel (CD active)
  188.  *  returns TRUE if channel busy
  189.  */
  190. static int
  191. hcdchk(base)
  192. int16 base;
  193. {
  194.     char isav;
  195.  
  196.     isav = disable();
  197.     cmd_8273(base, READ_A, 0);
  198.     while(!(inportb(base+STA) & CRBF))
  199.         ;
  200.     restore(isav);
  201.     return((inportb(base+RES) & CD) != 0);
  202. }
  203.  
  204. /*  TX interrupt service
  205.  *  if status register bit "TXIRA" is set, interrupt is final,
  206.  *  otherwise, interrupt is data request
  207.  */
  208. static void
  209. htxint(hp)
  210. register struct hapn *hp;
  211. {
  212.     char isav;
  213.     register int16 base;
  214.     int16 len;
  215.     char c;
  216.  
  217.     isav = disable();
  218.     hp->txints++;
  219.     base = hp->base;
  220.  
  221.     c = 0;
  222.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  223.         hp->tstate = IDLE;
  224.         free_p(hp->sndbuf);
  225.         hp->sndbuf = NULLBUF;
  226.  
  227.         /*  Read result  */
  228.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  229.             ;
  230.         c = inportb(base+TXI);
  231.  
  232.         /*  Test for tx abort  */
  233.         switch(c & 0x1f){
  234.         case DMA_URUN:
  235.             hp->t_urun++;
  236.             break;
  237.         case CTS_LOSS:
  238.             hp->ctsloss++;
  239.             break;
  240.         case ABORT_CMPLT:
  241.             hp->taborts++;
  242.             break;
  243.         }
  244.     }
  245.     switch(hp->tstate){
  246.     case IDLE:    /*  See if a buffer is ready to be sent  */
  247.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  248.             break;
  249.  
  250.     case DEFER:    /*  Busy-channel check  */
  251.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  252.             if(hcdchk(base)){
  253.                 hp->tstate = DEFER;
  254.                 break;
  255.             }
  256.         }
  257.         /*  Start transmitter  */
  258.         len = len_mbuf(hp->sndbuf);
  259.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  260.         hp->tstate = ACTIVE;
  261.         hp->tframes++;
  262.         break;
  263.     case ACTIVE:    /*  Get next byte to send  */
  264.         if(pullup(&hp->sndbuf, &c, 1) != 1){
  265.             cmd_8273(base, ABORT_TXF, 0);
  266.             hp->tstate = IDLE;
  267.         } else
  268.             outportb(base+TXD, c);
  269.         break;
  270.     }
  271.     restore(isav);
  272. }
  273.  
  274. /*  Attach a HAPN adaptor to the system
  275.  *  argv[0]:  hardware type, must be "hapn"
  276.  *  argv[1]:  I/O address, e.g. "0x310"
  277.  *  argv[2]:  vector, e.g. "2"
  278.  *  argv[3]:  mode, must be "ax25"
  279.  *  argv[4]:  interface name, e.g. "ha0"
  280.  *  argv[5]:  rx packet buffer size in bytes
  281.  *  argv[6]:  maximum transmission unit in bytes
  282.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  283.  */
  284. int
  285. hapn_attach(argc, argv)
  286. int argc;
  287. char *argv[];
  288. {
  289.     register struct interface *if_h;
  290.     extern struct interface *ifaces;
  291.     struct hapn *hp;
  292.     int dev, i;
  293.     char isav;
  294.     int hapn_init(), hapn_stop(), ax_send(), ax_output(),
  295.         hapn_raw();
  296.     void dohapn();
  297.     void (*getirq())();    /* Getirq is a function returning a pointer to
  298.                  * a function returning void */
  299.     static struct {
  300.         char *str;
  301.         char type;
  302.     } ch_access [] = { "csma", 0, "full", 1 };
  303.  
  304.     if(nhapn >= NHAPN){
  305.         printf("Too many HAPN adaptors\n");
  306.         return -1;
  307.     }
  308.     dev = nhapn++;
  309.  
  310.     /*  Initialize hardware constants */
  311.     hapn[dev].base = htoi(argv[1]);
  312.     hapn[dev].vec = htoi(argv[2]);
  313.  
  314.     /*  Save original interrupt vector  */
  315.     hapn[dev].oldvec = getirq(hapn[dev].vec);
  316.  
  317.     /*  Set new interrupt vector  */
  318.     setirq(hapn[dev].vec, h_handle[dev]);
  319.  
  320.     /*  Create new interface structure  */
  321.     if_h = (struct interface *) calloc(1,sizeof(struct interface));
  322.  
  323.     /*  Fill interface structure  */
  324.     if_h->name = malloc((unsigned) strlen(argv[4]) +1);
  325.     strcpy(if_h->name, argv[4]);
  326.     if_h->mtu = atoi(argv[6]);
  327.     if_h->dev = dev;
  328.     if_h->recv = dohapn;
  329.     if_h->stop = hapn_stop;
  330.     if_h->output = ax_output;
  331.     if_h->raw = hapn_raw;
  332.  
  333.     if(strcmp(argv[3], "ax25")){
  334.         printf("Mode %s unknown for interface %s\n", argv[3], argv[4]);
  335.         free(if_h->name);
  336.         free((char *) if_h);
  337.         return -1;
  338.     }
  339.     axarp();
  340.     if(mycall.call[0] == '\0'){
  341.         printf("set mycall first\n");
  342.         free(if_h->name);
  343.         free((char *) if_h);
  344.         return -1;
  345.     }        
  346.     if_h->send = ax_send;
  347.     if(if_h->hwaddr == NULLCHAR)
  348.         if_h->hwaddr = malloc(sizeof(mycall));
  349.     memcpy(if_h->hwaddr,(char *)&mycall,sizeof(mycall));
  350.     /*  Link the interface into the interface list  */
  351.     if_h->next = ifaces;
  352.     ifaces = if_h;
  353.  
  354.     /*  Fill the local data structure  */
  355.     hp = &hapn[dev];
  356.     hp->bufsiz = atoi(argv[5]);
  357.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  358.         if(!strcmp(argv[7], ch_access[i].str))
  359.             hp->mode = ch_access[i].type;
  360.  
  361.     /*  Initialize the hardware